// UCW_INT.CPP
// Interface to UCW
// This first vs. uses a remote message-based API
#include <fstream>
using namespace std;

#include <ctype.h>
#include <stdlib.h>

#include "ucw_int.h"

const int BUFFSIZE = 1024;

const int SYNCH_EXEC = 1981, SYNCH_EXEC_SC = 1982,
          GET_MSG = 1983,  GET_ERR = 1984, GET_FILEPOS = 1985,
		  RUN_PROGRAM = 1986, RECONNECT = 1987, SINGLE_STEP_PROGRAM = 1988,
          STEP_OVER_PROGRAM = 1989,
          EXPAND_MACRO = 1990, SET_FILEPOS = 1991, SET_LINE = 1992, EXPAND_FILE = 1993;

static char buffer[BUFFSIZE];

string UCW::home_dir()
{
  char* s = getenv("UC_HOME");
  if (! s) {      
     get_app_path(buffer,BUFFSIZE);	  
	 // *fix 0.5.1 if there's no UC_HOME, we need the _directory_
	 char* p = buffer + strlen(buffer);
	 while (*p != '\\') p--;
	 *p = 0;
	 return buffer;
  }
  else return s;
}

bool UCW::launch()
{ 
 int ret;
#ifdef _DEBUG
    ret = ::exec("/ucw/src/wdebug/ucw.exe");
#else
	string ucw_path;
	ucw_path = home_dir() + "/ucw.exe";
    ret = ::exec((char*)ucw_path.c_str());
#endif
	return ret;
}

int UCW::exec(string str, bool use_semicolon)
{
  m_pucw->set_text((char*)str.c_str());
  return cmd(use_semicolon ? SYNCH_EXEC_SC : SYNCH_EXEC);
}

int UCW::exec_with_pos(string str, string file, int line)
{
  m_pucw->set_text((char*)file.c_str());  
  cmd(SET_FILEPOS,line);
  return exec(str);
}

void UCW::get_err(string& buff)
{
 cmd(GET_ERR);
 m_pucw->get_text(buffer,sizeof(buffer));
 buff = buffer;
}

void UCW::get_msg(string& buff)
{
 cmd(GET_MSG);
  m_pucw->get_text(buffer,sizeof(buffer));
 buff = buffer;
}

int UCW::cmd(int icmd, int arg)
{
 return m_pucw->send_msg(WM_USER_PLUS,icmd,arg);
}

void process_result(char *res, bool strip_type)
{
   char buff[512];
   if (*res=='(' && strip_type) { 
       char *p = res;
       while(*p && *p != ')') p++;
	   p++;
       // skip leading space, if found
       if (*p == ' ') p++;
       char* eql = strchr(p,'=');
       if (eql) p = eql+2;
	   strcpy(buff,p);
	   strcpy(res,buff);
    }
	// *fix 1.1.4 nasty extra line feed!
	int len = strlen(res);
    if (res[len-1]=='\n') { res[len-1] = '\0'; len--; }    

    // removed quoted strings...
    if (*res == '\'' || *res == '\"') {
        res[len-1] = '\0';
        strcpy(buff,res+1);
        strcpy(res,buff);
    }
}

bool UCW::eval(string str, string& res, bool strip_type /* = true */)
{
  int ret = exec(str,true);
  if (ret == HALTED || ret == OK) {
    cmd(GET_MSG);
    m_pucw->get_text(buffer,sizeof(buffer));
    process_result(buffer,strip_type);
    res = buffer;
    return true;
  } else return false;
}

int UCW::get_filepos(string& buff)
{
 int line = cmd(GET_FILEPOS);
 m_pucw->get_text(buffer,sizeof(buffer));
 buff = buffer;
 return line;
}

int UCW::exec_msg(string str, string& result)
{
  int ret = exec(str,false);
  get_msg(result);
  return ret;
}

int UCW::exec_string_filter(int icmd, const string& str, string& result)
{
    int res;
    m_pucw->set_text((char*)str.c_str());
    res = cmd(icmd);
    m_pucw->get_text(buffer,sizeof(buffer));
    result = buffer;
    return res;
}

int UCW::expand_macro(string str, string& result)
{
    return exec_string_filter(EXPAND_MACRO,str,result);
}

int UCW::expand_include_file(string f, string& xf)
{
   return exec_string_filter(EXPAND_FILE,f,xf);
}

// writes our message-handling window handle where UCW can find it.
void UCW::init(void* handle)
{
  m_our_handle = handle;
  ofstream ofs("c:\\_q2k_.txt");  
  ofs << (int)handle << endl;
  ofs.close();
  
  if (connect())
	  cmd(RECONNECT);

  // switch to interactive debugging mode, errors-as-exceptions
  exec("#opt i+");
  exec("#opt e+");
  // also range checking of arrays, and reporting typedef aliases for types if possible
  exec("#opt R+");
  exec("#opt T+");
}

// finds the UCW handle which we will use as our remote server.
// it will refuse to connect to our _own_ UCW handle, (if it exists)
bool UCW::connect()
{
  int handle;
  ifstream ifs("c:\\_UCWS.TXT");  
  // a  better idea is to speak to the handle & see if it responds!
  if (!ifs || ifs.eof()) return false;
  ifs >> handle;
  if (m_our_handle != (void*)handle) {
    delete m_pucw;
    m_pucw = new TWin((Handle)handle);
    return true;
  } else return false;
}

UCW::UCW()
{
    m_pucw = NULL;
}
